package com.lian.community.service.text;

import com.qcloud.cos.utils.StringUtils;
import org.apache.commons.lang3.CharUtils;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.HashMap;
import java.util.Map;

@Service
public class SensitiveService implements InitializingBean{

    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(SensitiveService.class);

    @Override
    public void afterPropertiesSet() {
        String line;
        InputStream inputStream;
        InputStreamReader reader = null;
        BufferedReader bufferedReader;
        try {
            inputStream = new FileInputStream(new File("d:/sensitiveWord.txt"));
            reader = new InputStreamReader(inputStream);
            bufferedReader = new BufferedReader(reader);
            while ((line = bufferedReader.readLine()) != null) {
                addWord(line.trim());
            }
        } catch (IOException e) {
            e.printStackTrace();
            logger.error("读取敏感词失败！");
        } finally {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
                logger.error("reader close 失败！");
            }

        }
    }


    /**
     *
     * @param c
     * @return true表示此字符是特殊字符的
     */
    private boolean vaildChar(char c){
        int ic = (int)c;
        // 东亚文字 0x2E80 - 0x9FFF
        return !CharUtils.isAsciiAlphanumeric(c) && (ic < 0x2E80 || ic > 0x9FFF);
    }
    public String getFilter(String text){
        if(StringUtils.isNullOrEmpty(text)){
            return text;
        }
        // 如果直接把敏感词删除则把这句去掉就好
        String replacement = "***";
        TrieNode temp = rootNode;
        // begin是那个保存正在比较的字符串的开始字符位置的指针
        int begin = 0;
        // position是那个跟树结点一直对比的指针
        int position = 0;
        StringBuilder result = new StringBuilder();
        while (position < text.length()){
            char c = text.charAt(position);
            // 把混淆敏感词的特殊字符略过
            if(vaildChar(c)){
                // 这里的意思是，如果是刚开头判断，然后有些空格什么之类的，为了防止丢失，就把它加紧结果集里面
                if(temp == rootNode){
                    result.append(c);
                    ++begin;
                }
                ++position;
                continue;
            }
            temp = temp.getSubNode(c);
            if(temp == null){
                result.append(text.charAt(begin));
                position = begin + 1;
                begin = position;
                temp = rootNode;
            }else if (temp.keyWordEnd()){
                result.append(replacement);
                position += 1;
                begin = position;
                temp = rootNode;
            }else {
                ++position;
            }
        }
        result.append(text.substring(begin));
        return result.toString();

    }

    /**
     * 增加关键词
     * @param lineText
     */
    private void addWord(String lineText){
        TrieNode temp = rootNode;
        for(int i = 0;i < lineText.length();i++) {
            Character character = lineText.charAt(i);
            if(vaildChar(character)){
               continue;
            }
            TrieNode node = temp.getSubNode(character);
            if (node == null) {
                node = new TrieNode();
                temp.addSubNode(character, node);

            }
            temp = node;
            if(i == lineText.length() - 1){
                temp.setKeyWordEnd(true);
            }
        }
    }

    /**
     * 用于构造敏感词的前缀树
     */
    private class TrieNode{
        //是否为关键词的结尾
        private boolean end = false;
        //当前节点下的所有子节点
        private Map<Character, TrieNode> subNodes = new HashMap<>();

        public void addSubNode(Character key, TrieNode node){
            subNodes.put(key,node);
        }

        TrieNode getSubNode(Character key){
            return subNodes.get(key);
        }

        boolean keyWordEnd(){
            return end;
        }

        void setKeyWordEnd(boolean end){
            this.end = end;
        }

    }
    private TrieNode rootNode = new TrieNode();

}
